package com.topvision.camerasdk.video;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.ImageView;

import com.topvision.camerasdk.camera.CameraActivity;
import com.topvision.camerasdk.camera.util.CameraUtil;
import com.topvision.camerasdk.utils.CameraSettingsUtil;
import com.topvision.camerasdk.video.Interface.VideoInterface;
import com.topvision.camerasdk.video.test.SensorControler;
import com.topvision.commomsdk.uitl.AndroidUtils;
import com.topvision.commomsdk.uitl.FileUtil;
import com.topvision.commomsdk.uitl.PreferencesUtils;
import com.topvision.commomsdk.uitl.TvDeviceUtil;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * Created by Administrator on 2016/12/5.
 */

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback, MediaRecorder.OnErrorListener {

    public static final int MEDIA_TYPE_VIDEO = 2;
    private static final String TAG = "CameraDemo";
    private SurfaceHolder mHolder;
    private Camera mCamera;
    private MediaRecorder mMediaRecorder;
    Context context;
    File currentFile;
    VideoInterface videoInterface;
    SensorControler mSensorControler;
    //码率
    int bitRate = 0;

    /**
     * 开始录制
     *
     * @param @return
     * @return boolean
     * @throws
     * @Title: startRecording
     * @Description:
     */
    public boolean startRecording() {
        if (prepareVideoRecorder()) {
            try {
                checkBlueAir();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }

            return true;
        } else {
            releaseMediaRecorder();
        }
        return false;
    }

    public void stopRecording(final Handler handler, ImageView ablumIv) {
        if (mMediaRecorder != null) {
            // 加了这段就不会报错
            mMediaRecorder.setOnErrorListener(null);
            mMediaRecorder.setPreviewDisplay(null);
            try {
                mMediaRecorder.stop();
                mMediaRecorder.release();
                mMediaRecorder = null;
                if (mAudioManager.isBluetoothScoOn()) {
                    mAudioManager.setBluetoothScoOn(false);
                    mAudioManager.stopBluetoothSco();
                }

            } catch (IllegalStateException e) {
                Log.w("Yixia", "stopRecord", e);
            } catch (RuntimeException e) {
                Log.w("Yixia", "stopRecord", e);
            } catch (Exception e) {
                Log.w("Yixia", "stopRecord", e);
            }
            if (videoInterface != null) {
                videoInterface.isRecording(false);
            }
            createThumbnail(currentFile, handler, ablumIv);
        }
        releaseMediaRecorder();
    }

    public boolean isRecording() {
        return mMediaRecorder != null;
    }

    public CameraPreview(Context context) {
        super(context);
        mHolder = getHolder();
        mHolder.addCallback(this);
        this.context = context;
    }

    /**
     * 获取照相机对象
     *
     * @param @return
     * @return Camera
     * @throws
     * @Title: getCameraInstance
     * @Description:
     */
    public Camera getCameraInstance() {
        if (mCamera == null) {
            try {
                mCamera = Camera.open();
                if (mCamera != null) {
                    setCameraParameters(mCamera);
                }
            } catch (Exception e) {
                Log.d(TAG, "camera is not available");
                e.printStackTrace();
            }

        }

        return mCamera;
    }

    public void surfaceCreated(SurfaceHolder holder) {
        mCamera = getCameraInstance();
        try {
            if (mCamera != null) {
                mSensorControler = SensorControler.getInstance(context);
                mSensorControler.restFoucs();
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            } else {
                AndroidUtils.showTips(context, "camera is not available");
            }
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 设置Camera参数
     *
     * @param @param camera
     * @return void
     * @throws
     * @Title: setCameraParameters
     * @Description:
     */
    private void setCameraParameters(Camera camera) {
        Camera.Parameters params = camera.getParameters();
        //  params.setPreviewFrameRate(30);
//        params.setFlashMode("auto");
        if (params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
            params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        } else if (params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
            params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        }
//        if (MediaRecorderActivity.mActivity != null) {
//            Camera.Size optimalPreviewSize = CameraUtil.getDesiredPreviewSize(MediaRecorderActivity.mActivity, params);
//            params.setPreviewSize(optimalPreviewSize.width, optimalPreviewSize.height);
//            Log.e("tvLog", "optimalPreviewSize.width=" + optimalPreviewSize.width + "optimalPreviewSize.height=" + optimalPreviewSize.height);
//        }
        params = CameraSettingsUtil.geFromSettings(context, params);
        Camera.Size maxSize = CameraUtil.getMaxPreviewSize(params);
        params.setPreviewSize(maxSize.width, maxSize.height);
        params.set("orientation", "landscape");
        mCamera.setParameters(params);
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        mHolder.removeCallback(this);
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        System.out.println("surfaceChanged");
    }

    private boolean prepareVideoRecorder() {

        // 获取用户设置的分辨率
        int resolution = PreferencesUtils.getInt(context,
                VideoSettingActivity.SHAREPREFERENCE_RESOLUTION,
                CamcorderProfile.QUALITY_480P);
        CamcorderProfile mProfile = CamcorderProfile.get(resolution);
        if (mMediaRecorder == null) {
            mMediaRecorder = new MediaRecorder();
            mMediaRecorder.setOnErrorListener(this);
        } else {
            mMediaRecorder.reset();
        }
        mCamera.setPreviewCallback(null);
        mCamera.stopPreview();
        mCamera.unlock();

        mMediaRecorder.setCamera(mCamera);

        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

        mMediaRecorder.setOutputFormat(mProfile.fileFormat); // 设置视频的输出格式
        mMediaRecorder.setAudioEncoder(mProfile.audioCodec); // 设置音频的编码格式
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // 设置视频的编码格式
        currentFile = getOutputMediaFile();
        mMediaRecorder.setOutputFile(currentFile.toString());
        mMediaRecorder.setVideoSize(mProfile.videoFrameWidth,
                mProfile.videoFrameHeight);
        mMediaRecorder.setVideoFrameRate(mProfile.videoFrameRate);
        //http://blog.csdn.net/jefry_xdz/article/details/8299901 该博客上建议的码率
//        bitRate = mProfile.videoFrameWidth * mProfile.videoFrameHeight * 3;
        //200W
//        int low = (mProfile.videoFrameWidth * mProfile.videoFrameHeight * 3) / 2;
//        int high = mProfile.videoFrameWidth * mProfile.videoFrameHeight * 3 * 2
//        int low = (int) ((mProfile.videoFrameWidth * mProfile.videoFrameHeight * 3) / 2 * ration);
//        int high = (int) (mProfile.videoFrameWidth * mProfile.videoFrameHeight * 3 * 2 * ration);
        if (TvDeviceUtil.isTopTrueDevice()) {
            float ration = 0.5f;
            bitRate = (int) (mProfile.videoFrameWidth * mProfile.videoFrameHeight * 3 * ration);
        } else {
            bitRate = mProfile.videoFrameWidth * mProfile.videoFrameHeight * 3;
        }
        mMediaRecorder.setVideoEncodingBitRate(bitRate);
        mMediaRecorder.setAudioEncodingBitRate(mProfile.audioBitRate);
        Log.e("tvLog", "mProfile.videoBitRate=" + mProfile.videoBitRate + ",bitRate=" + bitRate + ",mProfile.videoCodec=" + mProfile.videoCodec + ",mProfile.videoFrameRate=" + mProfile.videoFrameRate + ",mProfile.audioBitRate=" + mProfile.audioBitRate + "，mProfile.fileFormat＝" + mProfile.fileFormat);
        //3078000
        mMediaRecorder.setPreviewDisplay(mHolder.getSurface());
        try {
            mMediaRecorder.prepare();
        } catch (Exception e) {
            Log.d(TAG, "Exception preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
            return false;
        }

        return true;
    }

    private AudioManager mAudioManager = null;

    private void checkBlueAir() {
        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        //检查是否A2DP蓝牙耳机音频路由是打开或关闭
        if (!mAudioManager.isBluetoothA2dpOn()) {
            mMediaRecorder.start();
            return;
        }
        if (!mAudioManager.isBluetoothScoAvailableOffCall()) {
            return;
        }
        // 蓝牙录音的关键，启动SCO连接，耳机话筒才起作用
        mAudioManager.startBluetoothSco();
        // 蓝牙SCO连接建立需要时间，连接建立后会发出ACTION_SCO_AUDIO_STATE_CHANGED消息，通过接收该消息而进入后续逻辑。
        // 也有可能此时SCO已经建立，则不会收到上述消息，可以startBluetoothSco()前先stopBluetoothSco()
        context.registerReceiver(new BroadcastReceiver() {

            @Override
            public void onReceive(Context context, Intent intent) {
                // TODO Auto-generated method stub
                int state = intent.getIntExtra(
                        AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
                if (AudioManager.SCO_AUDIO_STATE_CONNECTED == state) {
                    mAudioManager.setBluetoothScoOn(true); // 打开SCO
                    mAudioManager.adjustVolume(AudioManager.ADJUST_RAISE, 0);
                    if (mAudioManager.isBluetoothScoOn()) {
                        mMediaRecorder.start();
                        context.unregisterReceiver(this); // 别遗漏
                    }
                } else {// 等待一秒后再尝试启动SCO
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mAudioManager.startBluetoothSco();
                }

            }
        }, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
    }

    private void releaseMediaRecorder() {
        if (mMediaRecorder != null) {
            mMediaRecorder.reset();
            mMediaRecorder.release();
            mMediaRecorder = null;
            mCamera.lock();
        }
    }

    /**
     * 获取输出的文件地址
     * create at 2017/2/17 11:19
     */
    private File getOutputMediaFile() {
        File mediaStorageDir = new File(MediaRecorderActivity.TAKE_VIDEO_FOLDER);
        //创建所需目录
        FileUtil.createFolder(context, MediaRecorderActivity.TAKE_VIDEO_FOLDER);
        long timeStamp = new Date().getTime();
        File mediaFile = new File(mediaStorageDir, timeStamp + ".mp4");
        return mediaFile;
    }


    /**
     * 释放摄像头
     *
     * @param
     * @return void
     * @throws
     * @Title: freeCameraResource
     * @Description:
     */
    public void freeCameraResource() {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.lock();
            mCamera.release();
            mCamera = null;

        }
    }

    /**
     * 生成视频缩略图,
     *
     * @param @param handler
     * @return void
     * @throws
     * @Title: createThumbnail
     * @Description:
     */
    private void createThumbnail(final File file, final Handler handler,
                                 final ImageView ablumIv) {
        new Thread() {
            public void run() {
                Bitmap thumbnail = CameraUtil.getVidioBitmap(file.getPath(),
                        CameraActivity.DEFAULT_PICTURE_WIDTH, CameraActivity.DEFAULT_PICTURE_HEIGHT,
                        MediaStore.Video.Thumbnails.MINI_KIND);
                Message message = handler
                        .obtainMessage(MediaRecorderActivity.HANDLER_UPDATE_ALBUM);
                message.obj = thumbnail;
                handler.sendMessage(message);
            }

            ;
        }.start();

    }

    /**
     * 录制视屏回调方法
     *
     * @param @param mvideoInterface
     * @return void
     * @throws
     * @Title: setMvideoInterface
     * @Description:
     */
    public void setMvideoInterface(VideoInterface videoInterface) {
        this.videoInterface = videoInterface;

    }

    /**
     * @return the mVecordFile
     */
    public File getmVecordFile() {
        return currentFile;
    }


    /**
     * 手动聚焦
     *
     * @param point 触屏坐标
     */
    protected boolean onFocus(Point point, Camera.AutoFocusCallback callback) {
        if (mCamera == null) {
            return false;
        }

        Camera.Parameters parameters = null;
        try {
            parameters = mCamera.getParameters();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        //不支持设置自定义聚焦，则使用自动聚焦，返回

        if (Build.VERSION.SDK_INT >= 14) {

            if (parameters.getMaxNumFocusAreas() <= 0) {
                return focus(callback);
            }

            Log.i(TAG, "onCameraFocus:" + point.x + "," + point.y);

            List<Camera.Area> areas = new ArrayList<Camera.Area>();
            int left = point.x - 300;
            int top = point.y - 300;
            int right = point.x + 300;
            int bottom = point.y + 300;
            left = left < -1000 ? -1000 : left;
            top = top < -1000 ? -1000 : top;
            right = right > 1000 ? 1000 : right;
            bottom = bottom > 1000 ? 1000 : bottom;
            areas.add(new Camera.Area(new Rect(left, top, right, bottom), 100));
            parameters.setFocusAreas(areas);
            try {
                //本人使用的小米手机在设置聚焦区域的时候经常会出异常，看日志发现是框架层的字符串转int的时候出错了，
                //目测是小米修改了框架层代码导致，在此try掉，对实际聚焦效果没影响
                mCamera.setParameters(parameters);
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
                return false;
            }
        }


        return focus(callback);
    }

    private boolean focus(Camera.AutoFocusCallback callback) {
        try {
            mCamera.autoFocus(callback);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }


    @Override
    public void onError(MediaRecorder mr, int what, int extra) {
        Log.e("tvLog", "what=" + what + "extra=" + extra);
    }

}
